package ssh;
/*
 * Copyright (c) 2010-2020 Nathan Rajlich
 *
 *  Permission is hereby granted, free of charge, to any person
 *  obtaining a copy of this software and associated documentation
 *  files (the "Software"), to deal in the Software without
 *  restriction, including without limitation the rights to use,
 *  copy, modify, merge, publish, distribute, sublicense, and/or sell
 *  copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following
 *  conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *  OTHER DEALINGS IN THE SOFTWARE.
 */

import bean.HeadBean;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.java_websocket.WebSocket;
import org.java_websocket.drafts.Draft;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * A simple WebSocketServer implementation. Keeps track of a "chatroom".
 */
public class ChatServer extends WebSocketServer {

    public ChatServer(int port) throws UnknownHostException {
        super(new InetSocketAddress(port));
    }

    public ChatServer(InetSocketAddress address) {
        super(address);
    }

    public ChatServer(int port, Draft_6455 draft) {
        super(new InetSocketAddress(port), Collections.<Draft>singletonList(draft));
    }

    @Override
    public void onOpen(WebSocket conn, ClientHandshake handshake) {
        conn.send("Welcome to the server!"); //This method sends a message to the new client
        broadcast("new connection: " + handshake
                .getResourceDescriptor()); //This method sends a message to all clients connected
        System.out.println(
                conn.getRemoteSocketAddress().getAddress().getHostAddress() + " entered the room!");
    }

    @Override
    public void onClose(WebSocket conn, int code, String reason, boolean remote) {
        broadcast(conn + " has left the room!");
        System.out.println(conn + " has left the room!");
    }

    @Override
    public void onMessage(WebSocket conn, String message) {
        System.out.println("收到字符消息：" + message);
        if ("connect".equals(message)) {
            //管理端连接
            broadcast("{\"msg_id\":\"MSG_FRONTEND_CONN_REQ_0.07259927104988684\",\"msg_type\":4,\"payload_len\":124,\"service_type\":1,\"timestamp\":0}" + "\n\r\n\r" + "{\"device_name\":\"LEGatewayAuto_BJ4G29O23T\",\"product_key\":\"a1bAhApQDS0\",\"tenant_token\":\"186ae294-9cc9-49c4-9ef7-f654519e0913\"");
        } else if ("l".equals(message)) {
            broadcast("{\"token\":\"" + sessionId + "\",\"timestamp\":" + System.currentTimeMillis() + ",\"payload_len\":1,\"service_type\":1,\"msg_type\":22,\"msg_id\":\"MSG_FROM_FRONTEND_TO_BACKEND_0.6639357007215845\"}" + "\n\r\n\r" + "l");
        } else if ("s".equals(message)) {
            broadcast("{\"token\":\"" + sessionId + "\",\"timestamp\":" + System.currentTimeMillis() + ",\"payload_len\":1,\"service_type\":1,\"msg_type\":22,\"msg_id\":\"MSG_FROM_FRONTEND_TO_BACKEND_0.6639357007215845\"}" + "\n\r\n\r" + "s");
        } else if ("=".equals(message)) {
            broadcast("{\"token\":\"" + sessionId + "\",\"timestamp\":" + System.currentTimeMillis() + ",\"payload_len\":1,\"service_type\":1,\"msg_type\":22,\"msg_id\":\"MSG_FROM_FRONTEND_TO_BACKEND_0.6639357007215845\"}" + "\n\r\n\r");
        }
    }

    /**
     * 组装网关指令数据包
     *
     * @param datas
     * @return
     */
    private byte[] packageMessage(byte[] datas) {
        String header = "{\"token\":\"" + sessionId + "\",\"timestamp\":" + System.currentTimeMillis() + ",\"payload_len\":" + datas.length + ",\"service_type\":1,\"msg_type\":22,\"msg_id\":\"MSG_FROM_FRONTEND_TO_BACKEND_0.6639357007215845\"}" + "\n\r\n\r";
        byte[] headerBytes = header.getBytes(StandardCharsets.UTF_8);
        byte[] temp = new byte[datas.length + headerBytes.length];
        System.arraycopy(headerBytes, 0, temp, 0, headerBytes.length);
        System.arraycopy(datas, 0, temp, headerBytes.length, datas.length);
        return temp;
    }

    String sessionId = null;

    private final Set<WebSocket> clients = new HashSet<>();
    private final Set<WebSocket> sshdService = new HashSet<>();
    private int clientPort = 0;

    @Override
    public void onMessage(WebSocket conn, ByteBuffer message) {
        //broadcast(message.array());
        byte[] messageBytes = message.array();
        String data = new String(messageBytes);
        String[] datas = data.split("\n\r\n");
        System.out.println("收到客户端消息：" + data);
        if (datas == null) {
            return;
        }

        if ("hello".equals(datas[0])) {
            clientPort = conn.getRemoteSocketAddress().getPort();
            System.out.println("ssh客户端来了");
            clients.add(conn);
            broadcast("欢迎光临！", clients);
            return;
        }

        if (conn.getRemoteSocketAddress().getPort() == clientPort) {
            //客户端
            //组装数据包
            byte[] temp = packageMessage(messageBytes);
            //发送数据包给网关
            broadcast(temp, sshdService);
            return;
        }

        if (sshdService.size() == 0) {
            sshdService.add(conn);
        }

        HeadBean headBean = null;
        String payload = null;
        for (int i = 0; i < datas.length; i++) {
            if (i == 0) {
                System.out.println("头部：" + datas[i]);
                headBean = JSON.parseObject(datas[i], HeadBean.class);//反序列化
            } else if (i == 1) {
                payload = datas[i];
                System.out.println("payload:" + payload);
            } else if (i == 2) {
                if (datas[2] != null && datas[2].contains("session_id")) {
                    JSONObject session = JSON.parseObject(datas[2]);
                    sessionId = session.getString("session_id");
                }

            } else {
                System.out.println("其他:" + datas[i]);
            }
        }
        if (headBean != null) {
            if ("msg_id_for_handshake".equals(headBean.getMsg_id())) {
                //登录请求响应
                broadcast("{\"msg_id\":\"msg_id_for_handshake\",\"msg_type\":0,\"payload_len\":46,\"service_type\":0,\"timestamp\":1618192835,\"token\":\"\"}" + "\n\r\n\r" + "{\"code\":0,\"message\":\"online successfully\"}", sshdService);
            }
        }
        if ("SSH-2.0-OpenSSH_8.1".equals(payload)) {
            //ssh版本协议
            broadcast("{\"msg_id\":\"MSG_LOGIN_0.8334334045969569\",\"msg_type\":22,\"payload_len\":27,\"service_type\":1,\"timestamp\":1618216984755,\"token\":\"" + sessionId + "\"}" + "\n\r\n\r" + "SSH-2.0-SSHD-COMMON-2.1.0", sshdService);
            broadcast("{\"msg_id\":\"MSG_LOGIN_0.8334334045969569\",\"msg_type\":22,\"payload_len\":856,\"service_type\":1,\"timestamp\":1618216984755,\"token\":\"" + sessionId + "\"}", sshdService);
        } else {
            //发送给客户端
            if (payload != null && clients.size() > 0) {
                broadcast(payload.getBytes(StandardCharsets.UTF_8), clients);
            }
        }
    }

    @Override
    public void broadcast(String text) {
        System.out.println("发送数据给网关...↓");
        System.out.println(text);
        super.broadcast(text);
    }

    public static void main(String[] args) throws InterruptedException, IOException {
        int port = 443;
        ChatServer s = new ChatServer(port);
        s.start();
        System.out.println("ChatServer started on port: " + s.getPort());

        BufferedReader sysin = new BufferedReader(new InputStreamReader(System.in));
        while (true) {
            String in = sysin.readLine();
            s.broadcast(in);
            if (in.equals("exit")) {
                s.stop(1000);
                break;
            }
        }
    }

    @Override
    public void onError(WebSocket conn, Exception ex) {
        ex.printStackTrace();
        if (conn != null) {
            // some errors like port binding failed may not be assignable to a specific websocket
        }
    }

    @Override
    public void onStart() {
        System.out.println("Server started!");
        setConnectionLostTimeout(0);
        setConnectionLostTimeout(100);
    }

}
